package com.yaohe.protocols;

/**
 * ProtocolFactory.java
 * 
 * 2011/4/25 
 * 协议封装工具
 * managed by daweijiang
 *
 */

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Date;
import java.util.HashMap;
import java.util.Random;

import com.google.protobuf.ByteString;
import com.yaohe.common.ActiveCoupon;
import com.yaohe.common.Coupon;
import com.yaohe.common.key.CouponId;
import com.yaohe.common.key.StoreId;
import com.yaohe.protocols.ProtocolProtos.Protocol;
import com.yaohe.protocols.ProtocolProtos.Protocol.AuthenticationResponse;
import com.yaohe.protocols.ProtocolProtos.Protocol.CouponDelete;
import com.yaohe.protocols.ProtocolProtos.Protocol.CouponFetch;
import com.yaohe.protocols.ProtocolProtos.Protocol.CouponOrderNumQuery;
import com.yaohe.protocols.ProtocolProtos.Protocol.CouponPublish;
import com.yaohe.protocols.ProtocolProtos.Protocol.CouponQuery;
import com.yaohe.protocols.ProtocolProtos.Protocol.CouponUseConsumer;
import com.yaohe.protocols.ProtocolProtos.Protocol.CouponUseStore;
import com.yaohe.protocols.ProtocolProtos.Protocol.FunctionType;
import com.yaohe.protocols.ProtocolProtos.Protocol.Location;
import com.yaohe.protocols.ProtocolProtos.Protocol.PCoupon;
import com.yaohe.protocols.ProtocolProtos.Protocol.ProtocolType;


public class ProtocolFactory {
	//封装错误代码
	public static Protocol buildErrorMessage(ProtocolType pt, FunctionType ft, int err) {
		Protocol.Builder pBuilder = Protocol.newBuilder();
		pBuilder.setProtocolType(pt);
		pBuilder.setFunctionType(ft);
		pBuilder.setErrorCode(err);
		return pBuilder.build();
	}
	
	//封装协议 Authentication
	public static Protocol buildAuththenticationRequest(String storeLoginId, String password) {
		Protocol.Builder pBuilder = Protocol.newBuilder();
		pBuilder.setProtocolType(ProtocolType.REQUEST);
		pBuilder.setFunctionType(FunctionType.AUTHENTICATION);
		
		Protocol.Message.Builder mBuilder = Protocol.Message.newBuilder();
		{
			Protocol.Authentication.Builder authBuilder = Protocol.Authentication.newBuilder();
			authBuilder.setStoreLoginId(storeLoginId);
			authBuilder.setPassword(password);
			mBuilder.setAuthentication(authBuilder.build());
		}

		pBuilder.setMessage(mBuilder.build());
		
		return pBuilder.build();
	}
	
	
	public static Protocol.Location buildLocation(double lat, double lng){
		Protocol.Location.Builder lBuilder = Protocol.Location.newBuilder();
		lBuilder.setLatitude(lat);
		lBuilder.setLongitude(lng);
		return lBuilder.build();
	}
	public static Protocol buildCouponPublishRequest(byte[] storeIDinBytes, int token, Coupon coupon) {
		
		Protocol.Builder pBuilder = Protocol.newBuilder();
		pBuilder.setProtocolType(ProtocolType.REQUEST);
		pBuilder.setFunctionType(FunctionType.COUPON_PUBLISH);
		
		Protocol.Message.Builder mBuilder = Protocol.Message.newBuilder();
		{
			CouponPublish.Builder cpbuilder = CouponPublish.newBuilder();
			
			cpbuilder.setCoupon(parseCoupon_STORECLIENT(coupon));
			cpbuilder.setStoreID(ByteString.copyFrom(storeIDinBytes));
			cpbuilder.setToken(token);
			
			mBuilder.setCouponPublish(cpbuilder.build());
		}
		
		pBuilder.setMessage(mBuilder.build());
		return pBuilder.build();
	}
	
	//封装 CouponPublishResponse
	public static Protocol buildCouponPublishResponse(byte[] couponIDinBytes) {
		
		Protocol.Builder pBuilder = Protocol.newBuilder();
		pBuilder.setProtocolType(ProtocolType.RESPONSE);
		pBuilder.setFunctionType(FunctionType.COUPON_PUBLISH);
		
		Protocol.Message.Builder mBuilder = Protocol.Message.newBuilder();
		{
			Protocol.CouponPublishResponse.Builder cpbuilder = Protocol.CouponPublishResponse.newBuilder();
			
			cpbuilder.setCouponID(ByteString.copyFrom(couponIDinBytes));
			mBuilder.setCouponPublishResponse(cpbuilder.build());
		}
		
		pBuilder.setMessage(mBuilder.build());
		return pBuilder.build();
	}
	
	//封装 CouponDeleteRequest
	public static Protocol buildCouponDeleteRequest(byte[] storeIDinBytes, int token, byte[] couponIDinBytes) {
		
		Protocol.Builder pBuilder = Protocol.newBuilder();
		pBuilder.setProtocolType(ProtocolType.REQUEST);
		pBuilder.setFunctionType(FunctionType.COUPON_DELETE);
		
		Protocol.Message.Builder mBuilder = Protocol.Message.newBuilder();
		{
			CouponDelete.Builder cpbuilder = CouponDelete.newBuilder();
			
			cpbuilder.setCouponID(ByteString.copyFrom(couponIDinBytes));
			cpbuilder.setStoreID(ByteString.copyFrom(storeIDinBytes));
			cpbuilder.setToken(token);
			
			mBuilder.setCouponDelete(cpbuilder.build());
		}
		
		pBuilder.setMessage(mBuilder.build());
		return pBuilder.build();
	}
	
	//封装 CouponDeleteResponse
	public static Protocol buildCouponDeleteResponse(boolean success) {
		
		Protocol.Builder pBuilder = Protocol.newBuilder();
		pBuilder.setProtocolType(ProtocolType.RESPONSE);
		pBuilder.setFunctionType(FunctionType.COUPON_DELETE);
		
		Protocol.Message.Builder mBuilder = Protocol.Message.newBuilder();
		{
			Protocol.CouponDeleteResponse.Builder cpbuilder = Protocol.CouponDeleteResponse.newBuilder();
			
			cpbuilder.setSucess(success);
			mBuilder.setCouponDeleteResponse(cpbuilder.build());
		}
		
		pBuilder.setMessage(mBuilder.build());
		return pBuilder.build();
	}
	
	//封装 CouponQueryRequest by location
	public static Protocol buildCouponQueryRequest(byte[] userIDInBytes, double lat, double lng, int range) {
		
		Protocol.Builder pBuilder = Protocol.newBuilder();
		pBuilder.setProtocolType(ProtocolType.REQUEST);
		pBuilder.setFunctionType(FunctionType.COUPON_QUERY);
		
		Protocol.Message.Builder mBuilder = Protocol.Message.newBuilder();
		{
			CouponQuery.Builder cpbuilder = CouponQuery.newBuilder();
			
			cpbuilder.setUserCode(ByteString.copyFrom(userIDInBytes));
			
			Location.Builder  lbuilder = Location.newBuilder();
			lbuilder.setLatitude(lat);
			lbuilder.setLongitude(lng);
			
			cpbuilder.setLocation(lbuilder.build());
			cpbuilder.setRange(range);
			mBuilder.setCouponQuery(cpbuilder.build());
		}
		
		pBuilder.setMessage(mBuilder.build());
		return pBuilder.build();
	}
	
	//封装 CouponQueryRequest by storeID
	public static Protocol buildCouponQueryRequest(byte[] userIDinBytes, byte[] storeIDinBytes) {
		
		Protocol.Builder pBuilder = Protocol.newBuilder();
		pBuilder.setProtocolType(ProtocolType.REQUEST);
		pBuilder.setFunctionType(FunctionType.COUPON_QUERY);
		
		Protocol.Message.Builder mBuilder = Protocol.Message.newBuilder();
		{
			CouponQuery.Builder cpbuilder = CouponQuery.newBuilder();
			
			cpbuilder.setUserCode(ByteString.copyFrom(userIDinBytes));
			cpbuilder.setStoreID(ByteString.copyFrom(storeIDinBytes));
			
			mBuilder.setCouponQuery(cpbuilder.build());
		}
		
		pBuilder.setMessage(mBuilder.build());
		return pBuilder.build();
	}
	
	//封装 CouponQueryResponse
	public static Protocol buildCouponQueryResponse(List idList) {
		
		Protocol.Builder pBuilder = Protocol.newBuilder();
		pBuilder.setProtocolType(ProtocolType.RESPONSE);
		pBuilder.setFunctionType(FunctionType.COUPON_DELETE);
		
		Protocol.Message.Builder mBuilder = Protocol.Message.newBuilder();
		{
			Protocol.CouponQueryResponse.Builder cpbuilder = Protocol.CouponQueryResponse.newBuilder();
			
			cpbuilder.setIdList(parseIdList(idList));
			mBuilder.setCouponQueryResponse(cpbuilder.build());
		}
		
		pBuilder.setMessage(mBuilder.build());
		return pBuilder.build();
	}
	
	//封装 CouponFetchRequest
	public static Protocol buildCouponFetchRequest(byte[] userIDinBytes, List<CouponId> idList) {
		
		Protocol.Builder pBuilder = Protocol.newBuilder();
		pBuilder.setProtocolType(ProtocolType.REQUEST);
		pBuilder.setFunctionType(FunctionType.COUPON_FETCH);
		
		Protocol.Message.Builder mBuilder = Protocol.Message.newBuilder();
		{
			CouponFetch.Builder cpbuilder = CouponFetch.newBuilder();
			
			cpbuilder.setUserCode(ByteString.copyFrom(userIDinBytes));
			cpbuilder.setIdList(parseIdList(idList));
			
			mBuilder.setCouponFetch(cpbuilder.build());
		}
		
		pBuilder.setMessage(mBuilder.build());
		return pBuilder.build();
	}
	
	//封装 CouponFetchResponse
	public static Protocol buildCouponFetchResponse(List<ActiveCoupon> couponList) {
		
		Protocol.Builder pBuilder = Protocol.newBuilder();
		pBuilder.setProtocolType(ProtocolType.RESPONSE);
		pBuilder.setFunctionType(FunctionType.COUPON_FETCH);
		
		Protocol.Message.Builder mBuilder = Protocol.Message.newBuilder();
		{
			Protocol.CouponFetchResponse.Builder cpbuilder = Protocol.CouponFetchResponse.newBuilder();
			
			cpbuilder.setCouponList(parseCouponList(couponList));
			mBuilder.setCouponFetchResponse(cpbuilder.build());
		}
		
		pBuilder.setMessage(mBuilder.build());
		return pBuilder.build();
	}
	
	//封装 CouponUseConsumerRequest
	public static Protocol buildCouponUseConsumerRequest(byte[] userIDinBytes, byte[] couponIDinBytes) {
		
		Protocol.Builder pBuilder = Protocol.newBuilder();
		pBuilder.setProtocolType(ProtocolType.REQUEST);
		pBuilder.setFunctionType(FunctionType.COUPON_USE_CONSUMER);
		
		Protocol.Message.Builder mBuilder = Protocol.Message.newBuilder();
		{
			CouponUseConsumer.Builder cpbuilder = CouponUseConsumer.newBuilder();
			
			cpbuilder.setUserCode(ByteString.copyFrom(userIDinBytes));
			cpbuilder.setCouponID(ByteString.copyFrom(couponIDinBytes));
			
			mBuilder.setCouponUseConsumer(cpbuilder.build());
		}
		
		pBuilder.setMessage(mBuilder.build());
		return pBuilder.build();
	}
	
	//封装  CouponUseConsumerResponse
	public static Protocol buildCouponUseConsumerResponse(String authCode) {
		
		Protocol.Builder pBuilder = Protocol.newBuilder();
		pBuilder.setProtocolType(ProtocolType.RESPONSE);
		pBuilder.setFunctionType(FunctionType.COUPON_USE_CONSUMER);
		
		Protocol.Message.Builder mBuilder = Protocol.Message.newBuilder();
		{
			Protocol.CouponUseConsumerResponse.Builder cpbuilder = Protocol.CouponUseConsumerResponse.newBuilder();
			
			cpbuilder.setAuthCode(authCode);
		}
		
		pBuilder.setMessage(mBuilder.build());
		return pBuilder.build();
	}
	
	//封装 CouponUseStoreRequest
	public static Protocol buildCouponUseStoreRequest(byte[] storeIDinBytes, int token, byte[] couponIDinBytes, String authCode) {
		
		Protocol.Builder pBuilder = Protocol.newBuilder();
		pBuilder.setProtocolType(ProtocolType.REQUEST);
		pBuilder.setFunctionType(FunctionType.COUPON_USE_STORE);
		
		Protocol.Message.Builder mBuilder = Protocol.Message.newBuilder();
		{
			CouponUseStore.Builder cpbuilder = CouponUseStore.newBuilder();
			
			cpbuilder.setStoreID(ByteString.copyFrom(storeIDinBytes));
			cpbuilder.setCouponID(ByteString.copyFrom(couponIDinBytes));
			cpbuilder.setToken(token);
			cpbuilder.setAuthCode(authCode);
			
			mBuilder.setCouponUseStore(cpbuilder.build());
		}
		
		pBuilder.setMessage(mBuilder.build());
		return pBuilder.build();
	}
	
	//封装  CouponUseStoreResponse
	public static Protocol buildCouponUseStoreResponse(boolean success) {
		
		Protocol.Builder pBuilder = Protocol.newBuilder();
		pBuilder.setProtocolType(ProtocolType.RESPONSE);
		pBuilder.setFunctionType(FunctionType.COUPON_USE_STORE);
		
		Protocol.Message.Builder mBuilder = Protocol.Message.newBuilder();
		{
			Protocol.CouponUseStoreResponse.Builder cpbuilder = Protocol.CouponUseStoreResponse.newBuilder();
			
			cpbuilder.setSucess(success);
		}
		
		pBuilder.setMessage(mBuilder.build());
		return pBuilder.build();
	}
	
	//封装 CouponQrderNumQueryRequest
	public static Protocol buildCouponQrderNumQueryRequest(byte[] storeIDinBytes, byte[] couponIDinBytes) {
		
		Protocol.Builder pBuilder = Protocol.newBuilder();
		pBuilder.setProtocolType(ProtocolType.REQUEST);
		pBuilder.setFunctionType(FunctionType.COUPON_ORDER_NUM_QUERY);
		
		Protocol.Message.Builder mBuilder = Protocol.Message.newBuilder();
		{
			CouponOrderNumQuery.Builder cpbuilder = CouponOrderNumQuery.newBuilder();
			
			cpbuilder.setStoreID(ByteString.copyFrom(storeIDinBytes));
			cpbuilder.setCouponID(ByteString.copyFrom(couponIDinBytes));
			
			mBuilder.setCouponOrderNumQuery(cpbuilder.build());
		}
		
		pBuilder.setMessage(mBuilder.build());
		return pBuilder.build();
	}
	
	
	
	//封装  CouponQrderNumQueryResponse
	public static Protocol buildCouponQrderNumQueryResponse(int num) {
		
		Protocol.Builder pBuilder = Protocol.newBuilder();
		pBuilder.setProtocolType(ProtocolType.RESPONSE);
		pBuilder.setFunctionType(FunctionType.COUPON_ORDER_NUM_QUERY);
		
		Protocol.Message.Builder mBuilder = Protocol.Message.newBuilder();
		{
			Protocol.CouponOrderNumQueryResponse.Builder cpbuilder = Protocol.CouponOrderNumQueryResponse.newBuilder();
			
			cpbuilder.setOrderNum(num);
		}
		
		pBuilder.setMessage(mBuilder.build());
		return pBuilder.build();
	}
	
	//封装 ActiveCoupon, for server
	public static PCoupon parseActiveCoupon_SERVER(ActiveCoupon coupon){
		ByteBuffer b1 = ByteBuffer.allocate(8);
		b1.order(ByteOrder.BIG_ENDIAN);
		b1.putLong(coupon.staticInfo.begin.getTime());
		
		ByteBuffer b2 = ByteBuffer.allocate(8);
		b2.order(ByteOrder.BIG_ENDIAN);
		b2.putLong(coupon.staticInfo.end.getTime());
		
		PCoupon.Builder cbuilder = PCoupon.newBuilder();
		cbuilder.setCouponID(ByteString.copyFrom(coupon.staticInfo.id.getBytes()));
		cbuilder.setStoreName(coupon.staticInfo.storeName);
		cbuilder.setStoreAddress(coupon.staticInfo.storeAddress);
		cbuilder.setStoreID(ByteString.copyFrom(coupon.staticInfo.storeId.getBytes()));
		cbuilder.setBeginTime(ByteString.copyFrom(b1.array()));
		cbuilder.setEndTime(ByteString.copyFrom(b2.array()));
		cbuilder.setAmount(coupon.staticInfo.amount);
		cbuilder.setRemainingAmount(coupon.getCouponRemaining());
		cbuilder.setContent(coupon.staticInfo.description);
		cbuilder.setUseInMinutes(coupon.staticInfo.useInMinutes);
		cbuilder.setPicID(coupon.staticInfo.picID);
		
		return cbuilder.build();
	}
	
	//封装 Coupon, for client
	public static PCoupon parseCoupon_STORECLIENT(Coupon coupon){
		ByteBuffer b1 = ByteBuffer.allocate(8);
		b1.order(ByteOrder.BIG_ENDIAN);
		b1.putLong(coupon.begin.getTime());
		
		ByteBuffer b2 = ByteBuffer.allocate(8);
		b2.order(ByteOrder.BIG_ENDIAN);
		b2.putLong(coupon.end.getTime());
		
		PCoupon.Builder cbuilder = PCoupon.newBuilder();
		//cbuilder.setCouponID(ByteString.copyFrom(coupon.id.getBytes()));
		cbuilder.setStoreID(ByteString.copyFrom(coupon.storeId.getBytes()));
		cbuilder.setBeginTime(ByteString.copyFrom(b1.array()));
		cbuilder.setEndTime(ByteString.copyFrom(b2.array()));
		cbuilder.setAmount(coupon.amount);
		cbuilder.setContent(coupon.description);
		cbuilder.setUseInMinutes(coupon.useInMinutes);
		cbuilder.setPicID(coupon.picID);
		
		return cbuilder.build();
	}
	
	public static Coupon decodeCoupon_SERVER(PCoupon pcoupon) {
		Calendar calendar = Calendar.getInstance();
		ByteBuffer b = ByteBuffer.wrap(pcoupon.getBeginTime().toByteArray());
		long beginL = b.getLong();
		calendar.setTimeInMillis(beginL);
		Date begin = calendar.getTime();
		
		b = ByteBuffer.wrap(pcoupon.getEndTime().toByteArray());
		long endL = b.getLong();
		calendar.setTimeInMillis(endL);
		Date end = calendar.getTime();
		
		ByteString sidString = pcoupon.getStoreID();
		StoreId sid = new StoreId(sidString.toByteArray());
		Coupon coupon = null;
		try {
			coupon = Coupon.buildCoupon(
					new CouponId(), /*If server needs to decode a coupon, the coupon does not have id yet*/
					sid, 
					pcoupon.getContent(), 
					begin, 
					end, 
					pcoupon.getAmount(), 
					pcoupon.getRemainingAmount(),
					pcoupon.getUseInMinutes(),
					pcoupon.getStyle()
					);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return coupon;
	}
	
	//解析 Coupon, for client consumer
	public static Coupon decodeCoupon_CLIENTCONSUMER(PCoupon pcoupon) throws Exception{
		Calendar calendar = Calendar.getInstance();
		ByteBuffer b = ByteBuffer.wrap(pcoupon.getBeginTime().toByteArray());
		b.order(ByteOrder.BIG_ENDIAN);
		
		long beginL = b.getLong();
		calendar.setTimeInMillis(beginL);
		Date begin = calendar.getTime();
		
		b = ByteBuffer.wrap(pcoupon.getEndTime().toByteArray());
		long endL = b.getLong();
		calendar.setTimeInMillis(endL);
		Date end = calendar.getTime();
		
		Coupon coupon = Coupon.buildCouponWithStoreInfo(
				new CouponId(pcoupon.getCouponID().toByteArray()),
				new StoreId(pcoupon.getStoreID().toByteArray()),
				pcoupon.getContent(), 
				begin, 
				end, 
				pcoupon.getAmount(), 
				pcoupon.getRemainingAmount(),
				pcoupon.getUseInMinutes(),
				pcoupon.getStyle(),
				pcoupon.getStoreName(),
				pcoupon.getStoreAddress());
		
		return coupon;
	}
	

	public static Protocol.IdList parseIdList(List<CouponId> idList){
		Protocol.IdList.Builder lBuilder = Protocol.IdList.newBuilder();
		
		for(int i=0; i<idList.size(); i++){
			lBuilder.addCouponID(ByteString.copyFrom(idList.get(i).getBytes()));
		}
		
		return lBuilder.build();
	}
	
	/*
	//解析 IdList
	public static List<Integer> decodeIdList (Protocol.IdList idList){
		List<Integer> list = idList.getCouponIDList();
		
		return list;
	}*/
	
	//封装 CouponList
	public static Protocol.CouponList parseCouponList(List<ActiveCoupon> couponList){
		Protocol.CouponList.Builder lBuilder = Protocol.CouponList.newBuilder();
		
		for(int i=0; i<couponList.size(); i++){
			lBuilder.addCoupon(parseActiveCoupon_SERVER(couponList.get(i)));
		}
		
		return lBuilder.build();
	}
	
	//解析 CouponList
	public static List<Coupon> decodeCouponList (Protocol.CouponList couponList) throws Exception{
		List<PCoupon> list = couponList.getCouponList();
		
		List<Coupon> decodeList = new ArrayList<Coupon>();
		
		for(int i =0; i < list.size(); i++){
			decodeList.add(decodeCoupon_CLIENTCONSUMER(list.get(i)));
		}
		
		return decodeList;
	}
}
